﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Fast.Framework.Interfaces;
using Fast.Framework.Extensions;
using Fast.Framework.Models;

namespace Fast.Framework
{

    /// <summary>
    /// 更新实现类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class UpdateProvider<T> : IUpdate<T>
    {

        /// <summary>
        /// Ado
        /// </summary>
        private readonly IAdo ado;

        /// <summary>
        /// 更新建造者
        /// </summary>
        public IUpdateBuilder UpdateBuilder { get; }

        /// <summary>
        /// Sql表达式选项
        /// </summary>
        private readonly SqlExpressionOptions sqlExpressionOptions;

        /// <summary>
        /// 构造放发
        /// </summary>
        /// <param name="ado">ado</param>
        /// <param name="insertBuilder">插入建造者</param>
        public UpdateProvider(IAdo ado, IUpdateBuilder updateBuilder)
        {
            this.ado = ado;
            UpdateBuilder = updateBuilder;
            sqlExpressionOptions = new SqlExpressionOptions()
            {
                IgnoreParameterExpression = true,
                DbType = ado.DbOptions.DbType
            };
        }

        /// <summary>
        /// 作为
        /// </summary>
        /// <param name="tableName">表名称</param>
        /// <returns></returns>
        public IUpdate<T> As(string tableName)
        {
            UpdateBuilder.TableName = DbSymbolMapper.identify[ado.DbOptions.DbType].Insert(1, tableName);
            return this;
        }

        /// <summary>
        /// 来自
        /// </summary>
        /// <returns></returns>
        public IUpdate<T, T2> From<T2>()
        {
            sqlExpressionOptions.IgnoreParameterExpression = false;
            UpdateBuilder.From.Add($"{UpdateBuilder.TableName} p0");
            UpdateBuilder.TableName = "p0";
            UpdateBuilder.From.Add($"{DbSymbolMapper.identify[ado.DbOptions.DbType].Insert(1, typeof(T2).GetTableName())} p{UpdateBuilder.From.Count}");
            return new UpdateProvider<T, T2>(ado, UpdateBuilder);
        }

        /// <summary>
        /// 条件
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <returns></returns>
        public IUpdate<T> Where(Expression<Func<T, bool>> expression)
        {
            var sqlInfo = expression.ResolveSql(sqlExpressionOptions);
            UpdateBuilder.Where.Add(sqlInfo.WhereFormat());
            UpdateBuilder.Parameters.Append(sqlInfo.SqlParameters);
            return this;
        }

        /// <summary>
        /// 条件
        /// </summary>
        /// <param name="whereColumns">条件列</param>
        /// <returns></returns>
        public IUpdate<T> Where(params string[] whereColumns)
        {
            var keys = typeof(T).GetPrimaryKey();
            if (whereColumns != null && whereColumns.Length > 0)
            {
                if (UpdateBuilder.IsBatch)
                {
                    UpdateBuilder.Set = string.Join(",", UpdateBuilder.ParametersList[0].Where(w => !keys.Exists(e => e == w.Key) && !whereColumns.ToList().Exists(e => e == w.Key))
                        .Select(s => $"{DbSymbolMapper.identify[ado.DbOptions.DbType].Insert(1, s.Key)} = {DbSymbolMapper.parameter[ado.DbOptions.DbType]}{s.Key}"));
                }
                else
                {
                    UpdateBuilder.Set = string.Join(",", UpdateBuilder.Parameters.Where(w => !keys.Exists(e => e == w.Key) && !whereColumns.ToList().Exists(e => e == w.Key))
                    .Select(s => $"{DbSymbolMapper.identify[ado.DbOptions.DbType].Insert(1, s.Key)} = {DbSymbolMapper.parameter[ado.DbOptions.DbType]}{s.Key}"));
                }
                foreach (var column in whereColumns)
                {
                    UpdateBuilder.Where.Add($"{DbSymbolMapper.identify[ado.DbOptions.DbType].Insert(1, column)} = {DbSymbolMapper.parameter[ado.DbOptions.DbType]}{column}");//条件列
                }
            }
            return this;
        }

        /// <summary>
        /// In条件
        /// </summary>
        /// <typeparam name="FieldsType">字段类型</typeparam>
        /// <param name="inFieldsName">In字段名称</param>
        /// <param name="values">值</param>
        /// <returns></returns>
        public IUpdate<T> In<FieldsType>(string inFieldsName, params FieldsType[] values)
        {
            return In(inFieldsName, values.ToList());
        }

        /// <summary>
        /// In条件
        /// </summary>
        /// <typeparam name="FieldsType">字段类型</typeparam>
        /// <param name="inFieldsName">In字段名称</param>
        /// <param name="values">值</param>
        /// <returns></returns>
        public IUpdate<T> In<FieldsType>(string inFieldsName, List<FieldsType> values)
        {
            var type = typeof(FieldsType);
            var sqlParameters = new Dictionary<string, FieldsType>().AddIdentityKey(values.ToList(), UpdateBuilder.Parameters.Count);
            UpdateBuilder.Where.Add($"{DbSymbolMapper.identify[ado.DbOptions.DbType].Insert(1, inFieldsName)} IN ({string.Join(",", sqlParameters.Keys.Select(s => $"{DbSymbolMapper.parameter[ado.DbOptions.DbType]}{s}"))})");
            UpdateBuilder.Parameters.Append(sqlParameters);
            return this;
        }

        /// <summary>
        /// In条件
        /// </summary>
        /// <typeparam name="FieldsType">字段类型</typeparam>
        /// <param name="expression">表达式</param>
        /// <param name="values">值</param>
        /// <returns></returns>
        public IUpdate<T> In<FieldsType>(Expression<Func<T, object>> expression, List<FieldsType> values)
        {
            var sqlInfo = expression.ResolveSql(sqlExpressionOptions);
            var sqlParameters = new Dictionary<string, FieldsType>().AddIdentityKey(values, UpdateBuilder.Parameters.Count);
            UpdateBuilder.Where.Add(sqlInfo.InFormat(DbSymbolMapper.parameter[ado.DbOptions.DbType], sqlParameters));
            UpdateBuilder.Parameters.Append(sqlParameters);
            return this;
        }

        /// <summary>
        /// NotIn条件
        /// </summary>
        /// <typeparam name="FieldsType">字段类型</typeparam>
        /// <param name="notInFieldsName">Not In字段名称</param>
        /// <param name="values">值</param>
        /// <returns></returns>
        public IUpdate<T> NotIn<FieldsType>(string notInFieldsName, params FieldsType[] values)
        {
            return NotIn(notInFieldsName, values.ToList());
        }

        /// <summary>
        /// NotIn条件
        /// </summary>
        /// <typeparam name="FieldsType">字段类型</typeparam>
        /// <param name="notInFieldsName">Not In字段名称</param>
        /// <param name="values">值</param>
        /// <returns></returns>
        public IUpdate<T> NotIn<FieldsType>(string notInFieldsName, List<FieldsType> values)
        {
            var type = typeof(FieldsType);
            var sqlParameters = new Dictionary<string, FieldsType>().AddIdentityKey(values.ToList(), UpdateBuilder.Parameters.Count);
            UpdateBuilder.Where.Add($"{DbSymbolMapper.identify[ado.DbOptions.DbType].Insert(1, notInFieldsName)} NOT IN ({string.Join(",", sqlParameters.Keys.Select(s => $"{DbSymbolMapper.parameter[ado.DbOptions.DbType]}{s}"))})");
            UpdateBuilder.Parameters.Append(sqlParameters);
            return this;
        }

        /// <summary>
        /// NotIn条件
        /// </summary>
        /// <typeparam name="FieldsType">字段类型</typeparam>
        /// <param name="expression">表达式</param>
        /// <param name="values">值</param>
        /// <returns></returns>
        public IUpdate<T> NotIn<FieldsType>(Expression<Func<T, object>> expression, List<FieldsType> values)
        {
            var sqlInfo = expression.ResolveSql(sqlExpressionOptions);
            var sqlParameters = new Dictionary<string, FieldsType>().AddIdentityKey(values, UpdateBuilder.Parameters.Count);
            UpdateBuilder.Where.Add(sqlInfo.NotInFormat(DbSymbolMapper.parameter[ado.DbOptions.DbType], sqlParameters));
            UpdateBuilder.Parameters.Append(sqlParameters);
            return this;
        }

        /// <summary>
        /// 执行
        /// </summary>
        /// <returns></returns>
        public async Task<int> ExecuteAsync()
        {
            if (!UpdateBuilder.IsBatch)
            {
                return await ado.ExecuteNonQueryAsync(this.ToString(), ado.SqlParametersBuild(UpdateBuilder.Parameters));
            }
            var dbParameterList = UpdateBuilder.ParametersList.Select(s => ado.SqlParametersBuild(s)).ToList();
            return await ado.ExecuteNonQueryAsync(this.ToString(), dbParameterList);
        }

        /// <summary>
        /// 到字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return UpdateBuilder.ToString();
        }
    }

    /// <summary>
    /// 更新实现类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="T2"></typeparam>
    public class UpdateProvider<T, T2> : UpdateProvider<T>, IUpdate<T, T2>
    {

        /// <summary>
        /// ado
        /// </summary>
        private readonly IAdo ado;


        /// <summary>
        /// Sql表达式选项
        /// </summary>
        private readonly SqlExpressionOptions sqlExpressionOptions;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="ado"></param>
        /// <param name="updateBuilder"></param>
        public UpdateProvider(IAdo ado, IUpdateBuilder updateBuilder) : base(ado, updateBuilder)
        {
            this.ado = ado;
            sqlExpressionOptions = new SqlExpressionOptions()
            {
                DbType = ado.DbOptions.DbType
            };
        }

        /// <summary>
        /// 来自
        /// </summary>
        /// <typeparam name="T3"></typeparam>
        /// <returns></returns>
        IUpdate<T, T2, T3> IUpdate<T, T2>.From<T3>()
        {
            UpdateBuilder.From.Add($"{DbSymbolMapper.identify[ado.DbOptions.DbType].Insert(1, typeof(T3).GetTableName())} p{UpdateBuilder.From.Count}");
            return new UpdateProvider<T, T2, T3>(ado, UpdateBuilder);
        }

        /// <summary>
        /// 条件
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <returns></returns>
        public IUpdate<T, T2> Where(Expression<Func<T, T2, bool>> expression)
        {
            var sqlInfo = expression.ResolveSql(sqlExpressionOptions);
            UpdateBuilder.Where.Add(sqlInfo.WhereFormat());
            UpdateBuilder.Parameters.Append(sqlInfo.SqlParameters);
            return this;
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="expression">表达式</param>
        /// <returns></returns>
        public IUpdate<T, T2> Update(Expression<Func<T, T2, T>> expression)
        {
            var sqlInfo = expression.ResolveSql(sqlExpressionOptions);
            UpdateBuilder.Set = string.Join(",", sqlInfo.NewAssignMapper);
            UpdateBuilder.Parameters.Append(sqlInfo.SqlParameters);
            return this;
        }
    }

    /// <summary>
    /// 更新实现类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="T2"></typeparam>
    /// <typeparam name="T3"></typeparam>
    public class UpdateProvider<T, T2, T3> : UpdateProvider<T, T2>, IUpdate<T, T2, T3>
    {

        /// <summary>
        /// ado
        /// </summary>
        private readonly IAdo ado;

        /// <summary>
        /// Sql表达式选项
        /// </summary>
        private readonly SqlExpressionOptions sqlExpressionOptions;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="ado">ado</param>
        /// <param name="updateBuilder">更新建造者</param>
        public UpdateProvider(IAdo ado, IUpdateBuilder updateBuilder) : base(ado, updateBuilder)
        {
            this.ado = ado;
            sqlExpressionOptions = new SqlExpressionOptions()
            {
                DbType = ado.DbOptions.DbType
            };
        }

        /// <summary>
        /// 条件
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <returns></returns>
        public IUpdate<T, T2, T3> Where(Expression<Func<T, T2, T3, bool>> expression)
        {
            var sqlInfo = expression.ResolveSql(sqlExpressionOptions);
            UpdateBuilder.Where.Add(sqlInfo.WhereFormat());
            UpdateBuilder.Parameters.Append(sqlInfo.SqlParameters);
            return this;
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <param name="expression">表达式</param>
        /// <returns></returns>
        public IUpdate<T, T2, T3> Update(Expression<Func<T, T2, T3, T>> expression)
        {
            var sqlInfo = expression.ResolveSql(sqlExpressionOptions);
            UpdateBuilder.Set = string.Join(",", sqlInfo.NewAssignMapper);
            UpdateBuilder.Parameters.Append(sqlInfo.SqlParameters);
            return this;
        }
    }
}
